﻿/*
 Copyright (c) 2009 Alvin Cho (alvincho@risklib.com)
 Copyright (c) 2009 RiskLib.com
 
 This file is part of RiskLib.NET Project. See http://www.risklib.net for more information.
 
 RiskLib.NET is an open source project. Using of RiskLib.NET is free of charge.
 It is distributed under GNU General Public License version 2 (GPLv2).
 GPLv2 can be found at http://www.risklib.net/risklib/license.
 
 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.
*/
using System;
using System.Collections.Generic;
using System.Text;

namespace RiskLib
{
    public class ProductFundamentalDataList : Dictionary<IProductCode, FundamentalDataList>
    {
        public ProductFundamentalDataList UpdateList(ProductFundamentalDataList list)
        {
            ProductFundamentalDataList result = new ProductFundamentalDataList();
            foreach (IProductCode productCode in this.Keys)
            {
                if (list.ContainsKey(productCode))
                {
                    result.Add(productCode, list[productCode]);
                }
                else
                    result.Add(productCode, this[productCode]);
            }
            return result;
        }
    }
    public class AssetFieldDataListPath : Dictionary<int, ProductFundamentalDataList>
    {
        public AssetFieldDataListPath(int totalTime)
        {
            maxTime = totalTime;
        }
        private int maxTime;

        public int MaxTime
        {
            get { return maxTime; }
            set { maxTime = value; }
        }
    }

    public class HistoricalData
    {
        IProductCode productCode;

        public IProductCode ProductCode
        {
            get { return productCode; }
            set { productCode = value; }
        }
        DateTime date;

        public DateTime Date
        {
            get { return date; }
            set { date = value; }
        }
        Dictionary<FieldNameEnum, double> values = new Dictionary<FieldNameEnum, double>();

        public Dictionary<FieldNameEnum, double> Values
        {
            get { return values; }
            set { values = value; }
        }

        public static HistoricalData operator +(HistoricalData hdata1, HistoricalData hdata2)
        {

            HistoricalData result = new HistoricalData();
            result.Date = hdata1.Date;
            result.ProductCode = hdata1.ProductCode;
            foreach (FieldNameEnum fieldName in hdata1.Values.Keys)
            {
                result.Values.Add(fieldName, hdata1.Values[fieldName] + hdata2.values[fieldName]);
            }
            return result;
        }
        public static HistoricalData operator *(HistoricalData hdata1, double multiplier)
        {
            HistoricalData result = new HistoricalData();
            result.Date = hdata1.Date;
            result.ProductCode = hdata1.ProductCode;
            foreach (FieldNameEnum fieldName in hdata1.Values.Keys)
            {
                result.Values.Add(fieldName, hdata1.Values[fieldName] *multiplier);
            }
            return result;
        }
        public override string ToString()
        {
            string result = date.ToShortDateString()+" "+ productCode.ProductCode;
            foreach (FieldNameEnum fName in values.Keys)
            {
                result += " "+fName.ToString() + "=" + values[fName];
            }
            return result;
        }
    }
    public class CommonHistoricalDataList : Dictionary<IProductCode, HistoricalDataList>
    {
        public CommonHistoricalDataList(HistoricalDataList baseList)
        {
            base.Add(baseList.ProductCode, baseList);
            baseListProductCode = baseList.ProductCode;
        }
        public void Add(IProductCode key, HistoricalDataList value)
        {
            Add(value);
        }
        public void Add(HistoricalDataList hdList)
        {
            List<DateTime> badDateList = new List<DateTime>();
            HistoricalDataList newList=new HistoricalDataList(hdList.ProductCode);
            foreach (DateTime date in BaseList.Keys)
            {
                if (hdList.ContainsKey(date))
                    newList.Add(date, hdList[date]);
                else
                    badDateList.Add(date);
            }
            foreach (HistoricalDataList hl in Values)
            {
                foreach (DateTime date in badDateList)
                    if (hl.ContainsKey(date))
                        hl.Remove(date);
            }
            base.Add(newList.ProductCode, newList);
        }
        IProductCode baseListProductCode;
        public HistoricalDataList BaseList
        {
            get
            {
                return this[baseListProductCode];
            }
        }

        //public double CalculateCovariance(IProductCode p1, IProductCode p2, FieldNameEnum field)
        //{
        //    double[] x = new double[this[p1].Count];
        //    this[p1].CopyTo(field, x);
        //    double[] y = new double[this[p2].Count];
        //    this[p2].CopyTo(field, y);
        //    return Stat.Covariance(x, y);
        //}
    }
    public class DailyClosingList : SortedDictionary<IProductCode, HistoricalData>
    {
        public DateTime Date;
    }
    public class HistoricalDataList:SortedDictionary<DateTime,HistoricalData>
    {
        public HistoricalDataList():this(new SimpleProductCode("Default"))
        {
        }
        public HistoricalDataList(IProductCode code)
        {
            productCode = code;
        }
        public static HistoricalDataList operator+(HistoricalDataList hdList1, HistoricalDataList hdList2)
        {
            HistoricalDataList result = new HistoricalDataList(hdList1.ProductCode);
            foreach (DateTime date in hdList1.Keys)
            {
                if (hdList2.ContainsKey(date))
                    result.Add(date, hdList1[date] + hdList2[date]);
                else
                    result.Add(date, hdList1[date]);
            }
            foreach (DateTime date in hdList2.Keys)
            {
                if (!hdList1.ContainsKey(date))
                    result.Add(date, hdList2[date]);
            }
            return result;
        }
        public static HistoricalDataList operator*(HistoricalDataList hdList, double multiplier)
        {
            HistoricalDataList result = new HistoricalDataList(hdList.ProductCode);
            foreach (HistoricalData hdata in hdList.Values)
            {
                result.Add(hdata.Date, hdata * multiplier);
            }
            return result;
        }

        private IProductCode productCode;

        public IProductCode ProductCode
        {
            get { return productCode; }
            set { productCode = value; }
        }
        public void Add(DateTime key, HistoricalData value)
        {
            base.Add(key, value);
            //if (productCode == null&productCode.ProductCode!="Portfolio")
            //    productCode = value.ProductCode;
            //if (value.ProductCode == productCode)
            //    base.Add(key, value);
            //else
            //    throw new ArgumentException("Can't add differnent ProductCode into HistoricalDataList!");
        }
        public HistoricalDataList GetHistoricalData(DateTime startDate, DateTime endDate)
        {
            HistoricalDataList result = new HistoricalDataList(productCode);
            IEnumerator<HistoricalData> e = this.Values.GetEnumerator();
            HistoricalData hdata = (HistoricalData)e.Current;
            //if (hdata.Date >= startDate && hdata.Date <= endDate)
            //    result.Add(hdata.Date, hdata);
            while (e.MoveNext())
            {
                hdata = (HistoricalData)e.Current;
                if (hdata.Date >= startDate && hdata.Date <= endDate)
                    result.Add(hdata.Date, hdata);
            }
            return result;
        }
        public HistoricalDataList ConvertToHistoricalReturn(FieldNameEnum field)
        {
            HistoricalDataList result = new HistoricalDataList(productCode);
            result.productCode = productCode;
            IEnumerator<HistoricalData> e = this.Values.GetEnumerator();
            e.MoveNext();
            HistoricalData lastData = (HistoricalData)e.Current;
            while (e.MoveNext())
            {
                HistoricalData current = (HistoricalData)e.Current;
                if (current.Values.ContainsKey(field) && current.Values[field]!=0)
                {
                    HistoricalData retData=new HistoricalData();
                    retData.Date=current.Date;
                    retData.ProductCode=current.ProductCode;
                    retData.Values.Add(FieldNameEnum.DailyReturn,Math.Log(current.Values[field]/lastData.Values[field]));
                    result.Add(current.Date,retData);
                }
            }
            return result;
        }
        //public double CalculateVariance(FieldNameEnum field)
        //{
        //    double[] x = new double[this.Count];
        //    CopyTo(field, x);
        //    return Statistics.Stat.Variance(x);
        //}
        public void CopyTo(FieldNameEnum field, double[] array)
        {
            List<double> result = new List<double>();
            foreach (HistoricalData h in Values)
            {
                result.Add(h.Values[field]);
            }
            result.CopyTo(array);
        }
    }
}
